#include "heaptimer.h"

void HeapTimer::siftup_(size_t i) {
    assert(i >= 0 && i < heap_.size());
    size_t j = (i - 1) / 2; //得到父节点
    while(j >= 0) { //循环向上调整
        if(heap_[j] < heap_[i]) { break; } //大于父节点不调整
        SwapNode_(i, j); //交换，修改ref_中的记录
        //更新下标
        i = j; 
        j = (i - 1) / 2;
    }
}

void HeapTimer::SwapNode_(size_t i, size_t j) { //交换节点
    assert(i >= 0 && i < heap_.size());
    assert(j >= 0 && j < heap_.size());
    std::swap(heap_[i], heap_[j]);
    //更新记录
    ref_[heap_[i].id] = i;
    ref_[heap_[j].id] = j;
} 

bool HeapTimer::siftdown_(size_t index, size_t n) {//向下调整
    assert(index >= 0 && index < heap_.size());
    assert(n >= 0 && n <= heap_.size());
    size_t i = index;
    size_t j = i * 2 + 1;//左子节点
    while(j < n) {
        if(j + 1 < n && heap_[j + 1] < heap_[j]) j++; 
        if(heap_[i] < heap_[j]) break;
        SwapNode_(i, j);
        i = j;
        j = i * 2 + 1;
    }
    return i > index; //是否调整了
}

void HeapTimer::add(int id, int timeout, const TimeoutCallBack& cb) {
    assert(id >= 0);
    size_t i;
    if(ref_.count(id) == 0) {//还没有该节点
        // 插入到小根堆尾，调整堆
        i = heap_.size(); //插入位置
        ref_[id] = i; //保存信息
        heap_.push_back({id, Clock::now() + MS(timeout), cb});
        siftup_(i); //向上调整
    } 
    else {
        // 已有该结点，更新时间，调整堆 
        i = ref_[id]; //获取下标
        heap_[i].expires = Clock::now() + MS(timeout); //更新时间
        heap_[i].cb = cb;
        if(!siftdown_(i, heap_.size())) {
            siftup_(i);
        }
    }
}

void HeapTimer::doWork(int id) {
    // 删除指定id结点，并触发回调函数 
    if(heap_.empty() || ref_.count(id) == 0) {
        return;
    }
    size_t i = ref_[id];
    TimerNode node = heap_[i];
    node.cb();
    del_(i);
}

void HeapTimer::del_(size_t index) {
    // 删除指定位置的结点 
    assert(!heap_.empty() && index >= 0 && index < heap_.size());
    // 将要删除的结点换到队尾，然后调整堆 
    size_t i = index;
    size_t n = heap_.size() - 1;
    assert(i <= n);
    if(i < n) {
        SwapNode_(i, n);
        if(!siftdown_(i, n)) {
            siftup_(i);
        }
    }
    // 队尾元素删除
    ref_.erase(heap_.back().id);
    heap_.pop_back();
}

void HeapTimer::adjust(int id, int timeout) { //该节点有读写行为，更新时间
    // 调整指定id的结点 
    assert(!heap_.empty() && ref_.count(id) > 0);
    heap_[ref_[id]].expires = Clock::now() + MS(timeout);;
    siftdown_(ref_[id], heap_.size()); //时间变长了向下调整
}

void HeapTimer::tick() {
    // 清除超时结点 
    if(heap_.empty()) {
        return;
    }
    while(!heap_.empty()) { //循环检测根顶节点是否超时
        TimerNode node = heap_.front();
        if(std::chrono::duration_cast<MS>(node.expires - Clock::now()).count() > 0) { //没超时
            break; 
        }
        node.cb();//超时了，触发回调函数
        pop();
    }
}

void HeapTimer::pop() { //删除顶端节点
    assert(!heap_.empty());
    del_(0);
}

void HeapTimer::clear() { //清空
    ref_.clear();
    heap_.clear();
}

int HeapTimer::GetNextTick() { //获取下一个超时时间
    tick(); //超时的已经被清除
    size_t res = -1;
    if(!heap_.empty()) {
        res = std::chrono::duration_cast<MS>(heap_.front().expires - Clock::now()).count();
        if(res < 0) { res = 0; }
    }
    return res;
}